-
Notifications
You must be signed in to change notification settings - Fork 34
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
FIX: Performance optimisation for draft pages in treeview #181
Conversation
When draft pages are rendered in the treeview, an attempt to look up their live Version # is made. This leads to a cache miss and a subsequent query for each record. This change marks a cache as “complete” when all records of a given stage are pre-cached. This will suppress the record-specific query in the case of a cache miss.
Note that unless this fix is considered "critical" and rebased against the |
I tested on our key project. It doesn't look like it makes much of a difference. I've compared building the treeview for the This is comparing the original version to the patched version. We save 245 queries ( out of 2 381 ) and improve performance time by about 2.2%. @chillu I can review this in greater details if you want, but it's not going to resolve our treeview issues for our key project. |
Assuming this is the PR which reduces number of queries, it'll have a far bigger impact in SSP with a remote database than on your local. No need to set up Blackfire on SSP for this, but I think it's still worthwhile to get peer reviewed and merged this week. |
Note that this requires unpublished draft page to have much of an effect. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good and it should be functionally equivalent.
I've added some unit test to improve code coverage.
tests/php/VersionedTest.php
Outdated
$this->assertNull( | ||
Versioned::get_versionnumber_by_stage(VersionedTest\TestObject::class, Versioned::DRAFT, 888, true), | ||
'get_versionnumber_by_stage should return null when fetching a version number for unexisting object with prepopulate_versionnumber_caching' | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test is actually six or seven different tests, or different scenarios for one test. Can you please split it up or use a data provider?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about I split it in 4:
- 1 for getting an existing version number that is uncached and cached (2 assertions)
- 1 for getting an non-existing version number without the cache flag (1 assertion)
- 1 for getting an non-existing version number that is uncached and cached (2 assertions)
- 1 for getting an non-existing version number after a call to
prepopulate_versionnumber_cache
(1 assertion)
I'd rather avoid splitting the uncached/cached assertions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given Robbie is only available in EU timezone, I'll say: Yep, that sounds good ;)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry yeah sounds good
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds fine to me too, although you might find it easier with 6 separate tests using a data provider. And it's probably worth it if you think each of the assertions could fail in isolation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've switched to using a data provider and use a more thorough parameter coverage. I've moved the logic to a separate file because I need to have some setUp
and setUpBeforeClass
customisation.
The new tests actually found a bug, so I fix that as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Heh its funny, I've just commented on how unreadable the data provider refactor made this code ;) But I'd say it's good enough to merge
Move VersionedNumber caching to their own test suite and tweak them to use a data provider. Also, fix a bug when trying to bypass the completed cache and fetch an non existing version number.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Smart idea good job.
src/Versioned.php
Outdated
if ($cache) { | ||
if (isset(self::$cache_versionnumber[$baseClass][$stage][$id])) { | ||
return self::$cache_versionnumber[$baseClass][$stage][$id] ?: null; | ||
} elseif (isset(self::$cache_versionnumber[$baseClass][$stage]['_complete'])) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can technically be just an if
as you're returning in the preceding if
statement. Not a blocker though - super super minor.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think, I'll keep it as-is just to make it clear the second bit will only run if the first if statement is false.
OK this looks like we've addressed Robbie's feedback. Since I wrote this does @chillu want to merge? |
|
||
public function cacheDataProvider() | ||
{ | ||
return [ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As a sidenote, I find that data providers should only be used if the data within them is pretty self explanatory. If you find yourself going back and forth between the provider and the implementation (like I'm doing in this case), it's not helping readability. And in unit tests, I think readability overrules DRY principles.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@robbieaverill @chillu You guys are tough customers to please 😉
I'll keep it in mind for the next time.
When draft pages are rendered in the treeview, an attempt to look up
their live Version # is made. This leads to a cache miss and a
subsequent query for each record.
This change marks a cache as “complete” when all records of a given
stage are pre-cached. This will suppress the record-specific query
in the case of a cache miss.
Parent issue